#include "socket.h"
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <error.h>
#include <string.h>

/* get socket fd */
bool TcpClient::connect(const std::string& in_ip, const uint16_t in_port) {
    if (m_clientfd != -1) {
        std::cerr << "Client is already connected." << std::endl;
        return false;
    }
    m_ip = in_ip, m_port = in_port;
    if ((m_clientfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return false;

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(m_port);

    struct hostent* h;
    if ((h = gethostbyname(m_ip.c_str())) == nullptr) {
        std::cerr << "gethostbyname error: " << hstrerror(h_errno) << std::endl;
        close();
        return false;
    }
    memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);
    if (::connect(m_clientfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
        ::close(m_clientfd);
        m_clientfd = -1;
        return false;
    }
    return true;
}

bool TcpClient::send(const std::string& buffer) {
    if (m_clientfd == -1) {
        std::cerr << "Client is not connected." << std::endl;
        return false;
    }
    if (::send(m_clientfd, buffer.c_str(), buffer.size(), 0) <= 0) return false;
    return true;
}

bool TcpClient::recv(std::string &buffer, const size_t maxLen) {
    buffer.clear();
    buffer.resize(maxLen);
    int readn = ::recv(m_clientfd, &buffer[0], buffer.size(), 0);
    if (readn <= 0) {
        buffer.clear();
        return false;
    }
    buffer.resize(readn);
    return true;
}

bool TcpClient::close() {
    if (m_clientfd == -1) return false;
    ::close(m_clientfd);
    m_clientfd = -1;
    return true;
}